﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Collections.Generic;
using Gwn.Utilities.Extensions;

namespace Community.CsharpSqlite.WP.SqliteDataProvider.Base
{
    public class DataRow : DataBase, IDataRecord
    {
        private readonly List<DataColumn> _columns = new List<DataColumn>();

        private bool CheckOffset(int i)
        {
            return (i < 0 || i >= Count);
        }


        private void RequestedFieldDoesNotExist(int i, string fieldName = "")
        {
            var message = string.Format(
                    fieldName == "" ? "FIELD DOES NOT EXIST! Requested field offset {0}{1} (Field count={2})"
                                  : "FIELD DOES NOT EXIST! Requested field: ==>{1}<== Index={0}  (DataRow count={2})", 
                    i, fieldName, Count);

            Debug.WriteLine("\t" + message);
            foreach (var colName in _columns)
                Debug.WriteLine("\t+"+colName.Name.ToLower());
            Debug.WriteLine("-------------------");
            throw new IndexOutOfRangeException(message);


        }

        /// <summary>
        /// Gets the type of.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public T GetTypeOf<T>(string name)
        {
            var ordinal = GetOrdinal(name);

            if (CheckOffset(ordinal))
                RequestedFieldDoesNotExist(ordinal, name);

            return GetTypeOf<T>(ordinal);
        }

        /// <summary>
        /// Gets the type of.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public T GetTypeOf<T>(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);

            return this[i].GetTypeOf<T>();
        }

        /// <summary>
        /// Gets the boolean.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public bool GetBoolean(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);

            return this[i].GetTypeOf<bool>();
        }

        /// <summary>
        /// Gets the char.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public char GetChar(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);

            return this[i].GetTypeOf<char>();
        }

        /// <summary>
        /// Gets the name of the data type.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public string GetDataTypeName(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);

            return this[i].GetType().Name;
        }

        /// <summary>
        /// Gets the date time.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public System.DateTime GetDateTime(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);

            return this[i].GetTypeOf<DateTime>();
        }

        /// <summary>
        /// Gets the decimal.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public decimal GetDecimal(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);

            return this[i].GetTypeOf<decimal>();
        }

        /// <summary>
        /// Gets the double.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public double GetDouble(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);

            return this[i].GetTypeOf<double>();
        }

        /// <summary>
        /// Gets the type of the field.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public System.Type GetFieldType(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);

            return this[i].GetType();
        }

        /// <summary>
        /// Gets the string.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public string GetString(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);

            return this[i].GetTypeOf<string>();
        }

        /// <summary>
        /// Gets the int32.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public int GetInt32(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);

            return this[i].GetTypeOf<Int32>();
        }

        /// <summary>
        /// Gets the GUID.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public System.Guid GetGuid(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);

            return this[i].GetTypeOf<Guid>();
        }

        /// <summary>
        /// Gets or sets the field count.
        /// </summary>
        /// <value>The field count.</value>
        public int FieldCount { get { return Count; } set { } }


        /// <summary>
        /// Gets or sets the <see cref="System.Object"/> with the specified name.
        /// </summary>
        /// <value></value>
        public object this[string name]
        {
            get
            {

                var offset = FindNameOffset(name);
                return offset >= 0 ? this[offset] : null;
            }
            set
            {
                var col = _columns.FirstOrDefault(c => c.Name == name);
                if(col!=null)
                    throw new Exception(string.Format("Field name {0} already exist! ", name));

                _columns.Add(new DataColumn(name, value));
                Add(value);
            }
        }


        /// <summary>
        /// Gets the name.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public string GetName(int i)
        {
            if (CheckOffset(i))
                RequestedFieldDoesNotExist(i);


            if (i > _columns.Count - 1)
                return "Not Assigned";

            return _columns[i].Name;
        }

        /// <summary>
        /// Gets the ordinal.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public int GetOrdinal(string name)
        {
            return FindNameOffset(name);
        }

        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public object GetValue(int i)
        {
            return this[i];
        }

        /// <summary>
        /// Gets the columns.
        /// </summary>
        /// <returns></returns>
        public List<DataColumn> GetColumns()
        {
            return _columns;
        }

        private int FindNameOffset(string name)
        {
            int offset = 0;
            
            foreach (var colName in _columns)
            {
                if (colName.Name.ToLower() == name.ToLower())
                    return offset;

                offset++;
            }

            RequestedFieldDoesNotExist(-1, name);
            return -1;
        }



        /// <summary>
        /// Gets the data.
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns></returns>
        public IDataReader GetData(int i)
        {
            throw new System.NotImplementedException();
        }
        /// <summary>
        /// Determines whether [is DB null] [the specified i].
        /// </summary>
        /// <param name="i">The i.</param>
        /// <returns>
        /// 	<c>true</c> if [is DB null] [the specified i]; otherwise, <c>false</c>.
        /// </returns>
        public bool IsDBNull(int i)
        {
            throw new System.NotImplementedException();
        }
        public short GetInt16(int i)
        {
            throw new System.NotImplementedException();
        }
        public long GetInt64(int i)
        {
            throw new System.NotImplementedException();
        }
        public float GetFloat(int i)
        {
            throw new System.NotImplementedException();
        }
        public byte GetByte(int i)
        {
            throw new System.NotImplementedException();
        }
        public int GetBytes(int i, int fieldoffset, byte[] buffer, int length, int bufferoffset)
        {
            throw new System.NotImplementedException();
        }
        public int GetChars(int i, int fieldoffset, char[] buffer, int length, int bufferoffset)
        {
            throw new System.NotImplementedException();
        }
    }
}
